﻿using Oracle.DataAccess.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using WorkFlow.DBProxy;

namespace WorkFlow.Engine.NSPermission
{
    public class WfPermissionController
    {
        #region fileds

        private static readonly object LockObj = new object();
        private static volatile WfPermissionController _controller;
        private readonly List<WfOrganization> _orgsCollection;
        private readonly List<WfRole> _rolesCollection;
        private readonly List<WfUser> _usersCollection;

        #endregion fileds

        #region constuctor

        private WfPermissionController()
        {
            _orgsCollection = new List<WfOrganization>();
            _rolesCollection = new List<WfRole>();
            _usersCollection = new List<WfUser>();
        }

        /// <summary>
        ///     双重加锁 确保安全同时减少性能损失.
        /// </summary>
        /// <returns></returns>
        public static WfPermissionController CreatePermissionController()
        {
            if (_controller != null) return _controller;

            bool lockToken = false;
            try
            {
                Monitor.Enter(LockObj, ref lockToken);
                _controller = new WfPermissionController();
            }
            catch
            {
                return null;
            }
            finally
            {
                if (lockToken)
                {
                    Monitor.Exit(LockObj);
                }
            }
            return _controller;
        }

        #endregion constuctor

        #region self defined method

        /// <summary>
        ///     某个用户是否属于该角色
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="roleID"></param>
        /// <returns></returns>
        public bool UserIsInRole(int userID, int roleID)
        {
            WfUser user = GetUser(userID);
            return user != null && user.IsBelongToRole(roleID);
        }

        /// <summary>
        ///     某个用是否属于某组织
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="orgID"></param>
        /// <returns></returns>
        public bool UserIsInOrganization(int userID, int orgID)
        {
            WfUser user = GetUser(userID);
            return user.IsCreated && user.IsBelongToOrg(orgID);
        }

        /// <summary>
        ///     根据ID获取组织信息
        /// </summary>
        /// <param name="orgID"></param>
        /// <returns></returns>
        public WfOrganization GetOrgaization(int orgID)
        {
            int count = _orgsCollection.Count;
            for (int i = 0; i < count; i++)
            {
                if (_orgsCollection[i].ID == orgID) return _orgsCollection[i];
            }

            //如果不存在 create it
            var org = new WfOrganization(orgID);
            if (!org.IsCreated) return null;

            _orgsCollection.Add(org); //添加到集合
            return org;
        }

        /// <summary>
        ///     根据ID获取角色
        /// </summary>
        /// <param name="roleID"></param>
        /// <returns></returns>
        public WfRole GetRole(int roleID)
        {
            int count = _rolesCollection.Count;
            for (int i = 0; i < count; i++)
            {
                if (_rolesCollection[i].ID == roleID) return _rolesCollection[i];
            }
            //if not exists then create it
            var role = new WfRole(roleID);
            if (!role.IsCreated) return null;

            _rolesCollection.Add(role); //添加到集合
            return role;
        }

        /// <summary>
        ///     根据ID获取用户
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public WfUser GetUser(int userID)
        {
            int count = _usersCollection.Count;
            for (int i = 0; i < count; i++)
            {
                if (_usersCollection[i].ID == userID) return _usersCollection[i];
            }
            //if not exists then create it
            var user = new WfUser(userID);
            if (!user.IsCreated) return null;

            _usersCollection.Add(user); //添加到集合
            return user;
        }

        /// <summary>
        ///     检索用户ID是否在表达式所包含的用户ID中
        /// </summary>
        /// <param name="condtion"></param>
        /// <param name="userID"></param>
        public bool IsUserHasPrivilege(string condtion, int userID)
        {
            if (string.IsNullOrEmpty(condtion)) return false;
            WfUser user = GetUser(userID);
            /*
             * 解析如下字符串
             * org=1 and role=2 and user!=4
             * org role user三个关键字不能为其他的
             *  org=1
             */
            string con = condtion.ToLower().Replace("and", "");
            char[] chs = con.ToCharArray();
            int count = chs.Count();
            var tempvar = new StringBuilder(); //变量名
            var tempnum = new StringBuilder(); //值
            var tempOpt = new StringBuilder(); //操作符

            for (int i = 0; i < count; i++)
            {
                if (chs[i] >= 'a' && chs[i] <= 'z')
                {
                    //如果是字母
                    tempvar.Append(chs[i]);
                } //end if
                else if (chs[i] <= '9' && chs[i] >= '0')
                {
                    tempnum.Append(chs[i]);
                } // end if
                else if (chs[i] == '=' || chs[i] == '!')
                {
                    tempOpt.Append(chs[i]);
                } //end if
                else if (chs[i] == ' ' && (tempvar.Capacity > 0 && tempnum.Capacity > 0 && tempOpt.Capacity > 0))
                {
                    string key = tempvar.ToString();
                    string opt = tempOpt.ToString();
                    int value = Convert.ToInt32(tempnum.ToString());
                    bool tempIdent = false;
                    switch (key)
                    {
                        case "org":
                            tempIdent = user.IsBelongToOrg(value);
                            if (opt.Equals("!=")) tempIdent = !tempIdent;
                            if (!tempIdent) return false;
                            break;

                        case "role":
                            tempIdent = user.IsBelongToRole(value);
                            if (opt.Equals("!=")) tempIdent = !tempIdent;
                            if (!tempIdent) return false;
                            break;

                        case "user":
                            if (opt.Equals("!="))
                            {
                                if (value != userID) tempIdent = true;
                            }
                            else
                            {
                                if (value == userID) tempIdent = true;
                            }
                            if (!tempIdent) return false;
                            break;
                    }
                    //-----------清空数据
                    tempvar.Clear();
                    tempnum.Clear();
                    tempOpt.Clear();
                }
                // end if  if (chs[i] == ' ' && (tempvar.Capacity > 0 && tempnum.Capacity > 0 && tempOpt.Capacity > 0))
            }
            return true;
        }

        /// <summary>
        ///     检查用户是否拥有某组织和角色下的权限
        /// </summary>
        /// <param name="orgID"></param>
        /// <param name="roleID"></param>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool IsUserHasPrivilege(int orgID, int roleID, int userID)
        {
            WfUser user = GetUser(userID);
            if (user == null || !user.IsCreated) return false;
            return user.IsBelongToOrg(orgID) && user.IsBelongToRole(roleID);
        }

        /// <summary>
        ///     为运行库指活动指定新的权限用户(这时,要指定的组织就不能再为"抽象"组织了!)
        /// </summary>
        /// <param name="accessor">对于_ancestor,如果组织或角色不为空(即 0 ),就必须要有它说继承的ID</param>
        /// <param name="actID">运行库中的活动ID</param>
        /// <param name="nextActID">需要设置权限的活动库活动的ID</param>
        /// <param name="modifyUser">修改权限的用户</param>
        /// <returns></returns>
        public bool SetNewPrivilegesToRunAct(WfActAccessorStruct accessor, int nextActID, int modifyUser)
        {
            if (accessor._orgID > 0 && accessor._roleID > 0 && accessor._userID > 0)
                return false; //同一活动中,人和组织、角色间不能共存 ,但能排除
            /*
             var_next_act in number,
            var_derivedfrom_id in number,
            var_org_id in number,
            var_role_id in number,
            var_user_id in number,
            var_modify_user in number,
            returnvalue out number
             */
            OracleParameter[] obj =
            {
                new OracleParameter("var_next_act", OracleDbType.Int32, ParameterDirection.Input)
                {
                    Value = nextActID
                }, //0
                new OracleParameter("var_derivedfrom_id", OracleDbType.Int32, ParameterDirection.Input)
                {
                    Value = accessor._ancestorID
                }, //5
                new OracleParameter("var_org_id", OracleDbType.Int32, ParameterDirection.Input)
                {
                    Value = accessor._orgID
                }, //1
                new OracleParameter("var_role_id", OracleDbType.Int32, ParameterDirection.Input)
                {
                    Value = accessor._roleID
                }, //2
                new OracleParameter("var_user_id", OracleDbType.Int32, ParameterDirection.Input)
                {
                    Value = accessor._userID
                }, //3
                new OracleParameter("var_modify_user", OracleDbType.Int32, ParameterDirection.Input)
                {
                    Value = modifyUser
                }, //4
                new OracleParameter("returnvalue", OracleDbType.Int32, ParameterDirection.Output) //6
            };
            DB.ExecuteProc("setRunActPrivileges", obj);
            return int.Parse(obj[6].Value.ToString()) > 0;
        }

        /// <summary>
        ///     合并组织::将抽象组织替换为具体组织,同时剔除重复组织
        /// </summary>
        /// <param name="orgIDs"></param>
        /// <returns>返回合并后的具体组织ID列表</returns>
        public List<WfOrgStruct> UnionOrganizations(List<int> orgIDs)
        {
            int count = orgIDs == null ? 0 : orgIDs.Count;
            if (count == 0) return null;

            var list = new List<WfOrgStruct>();
            for (int i = 0; i < count; i++)
            {
                if (orgIDs == null) continue;
                WfOrganization org = GetOrgaization(orgIDs[i]);
                if (!org.IsCreated) return null;
                if (org.IsAbstractOrg == WfFieldCode.DbTrue)
                {
                    foreach (WfOrgStruct v in org._specificOrgsCollection)
                    {
                        if (!list.Contains(v)) list.Add(v);
                    }
                }
                else
                {
                    if (!IsExists(org.ID, list))
                        list.Add(new WfOrgStruct
                        {
                            _id = org.ID,
                            _name = org.Name,
                            _abstractID = org.AbstractOrg,
                            _runActID = 0
                        });
                }
            }
            return list;
        }

        /// <summary>
        ///     检查某组织是否存在于列表中
        /// </summary>
        /// <param name="orgID">组织ID</param>
        /// <param name="list">组织列表</param>
        /// <returns></returns>
        private static bool IsExists(int orgID, IReadOnlyList<WfOrgStruct> list)
        {
            int count = list == null ? 0 : list.Count;
            if (count == 0) return false;
            for (int i = 0; i < count; i++)
            {
                // ReSharper disable once PossibleNullReferenceException
                if (list[i]._id == orgID) return true;
            }
            return false;
        }

        #endregion self defined method
    }
}